import * as THREE from 'three/build/three.module'
import {Water} from 'three/examples/jsm/objects/Water'
import MapBoxGL from '!../mapbox/mapbox-gl';
import {RGBELoader} from "three/examples/jsm/loaders/RGBELoader";

class LakeLayer {

    constructor(geometry) {

        this.id = 'lake';
        this.type = 'custom';
        this.renderingMode = '3d';

        this.geometry = geometry;

        var modelOrigin = [118.1886863708496, 37.33150496664551];
        var modelAltitude = 0;
        var modelRotate = [Math.PI / 2, 0, 0];

        var modelAsMercatorCoordinate = MapBoxGL.MercatorCoordinate.fromLngLat(
            modelOrigin,
            modelAltitude
        );

        this.modelTransform = {
            translateX: modelAsMercatorCoordinate.x,
            translateY: modelAsMercatorCoordinate.y,
            translateZ: modelAsMercatorCoordinate.z,
            rotateX: modelRotate[0],
            rotateY: modelRotate[1],
            rotateZ: modelRotate[2],
            /* Since our 3D model is in real world meters, a scale transform needs to be
             * applied since the CustomLayerInterface expects units in MercatorCoordinates.
             */
            scale: modelAsMercatorCoordinate.meterInMercatorCoordinateUnits()
        };
    }

    onAdd(map, gl) {

        this.map = map;

        this.camera = new THREE.Camera();
        this.scene  = new THREE.Scene();

        const geometry = new THREE.BoxGeometry(30, 30, 30);
        const material = new THREE.MeshStandardMaterial();

        this.box = new THREE.Mesh(geometry, material);
        this.scene.add(this.box);

        // Water
        const waterGeometry = this.geometry;

        this.water = new Water(
            waterGeometry,
            {
                textureWidth: 512,
                textureHeight: 512,
                waterNormals: new THREE.TextureLoader().load('textures/waternormals.jpg', texture => {

                    texture.wrapS = texture.wrapT = THREE.RepeatWrapping;

                }),
                sunDirection: new THREE.Vector3(0.70707, 0.70707, 0.0),
                sunColor: 0xffffff,
                waterColor: 0x0080ff,
                distortionScale: 3.7,
                side: THREE.BackSide
            }
        );

        this.scene.add(this.water);

        this.renderer = new THREE.WebGLRenderer({
            canvas: this.map.getCanvas(),
            context: gl,
            antialias: true
        })

        this.renderer.toneMapping = THREE.ACESFilmicToneMapping;
        this.renderer.autoClear = false;
        this.renderer.physicallyCorrectLights = true;
        this.renderer.outputEncoding = THREE.sRGBEncoding;

        var pmremGenerator = new THREE.PMREMGenerator(this.renderer);
        pmremGenerator.compileEquirectangularShader();

        new RGBELoader().setDataType(THREE.UnsignedByteType).load('textures/pump_station_1k.hdr', dataTexture => {

            let envMap = pmremGenerator.fromEquirectangular(dataTexture).texture;
            pmremGenerator.dispose();

            this.scene.environment = envMap;
        })
    }

    render(gl, matrix) {

        const time = performance.now() * 0.001;

        this.box.position.y = Math.sin(time) * 20 + 5;
        this.box.rotation.x = time * 0.5;
        this.box.rotation.z = time * 0.51;

        this.water.material.uniforms['time'].value += 1.0 / 60.0;

        var rotationX = new THREE.Matrix4().makeRotationAxis(
            new THREE.Vector3(1, 0, 0),
            this.modelTransform.rotateX
        );
        var rotationY = new THREE.Matrix4().makeRotationAxis(
            new THREE.Vector3(0, 1, 0),
            this.modelTransform.rotateY
        );
        var rotationZ = new THREE.Matrix4().makeRotationAxis(
            new THREE.Vector3(0, 0, 1),
            this.modelTransform.rotateZ
        );

        var m = new THREE.Matrix4().fromArray(matrix);
        var l = new THREE.Matrix4()
            .makeTranslation(
                this.modelTransform.translateX,
                this.modelTransform.translateY,
                this.modelTransform.translateZ
            )
            .scale(
                new THREE.Vector3(
                    this.modelTransform.scale,
                    -this.modelTransform.scale,
                    this.modelTransform.scale
                )
            )
            .multiply(rotationX)
            .multiply(rotationY)
            .multiply(rotationZ);

        this.camera.projectionMatrix = m.multiply(l);
        this.renderer.resetState();
        this.renderer.render(this.scene, this.camera);
        this.map.triggerRepaint();
    }
}

export default LakeLayer